package com.spotalog.server.service.rest;

import static com.spotalog.shared.service.rest.Constants.PHOTO_INGEST_FIELD;
import static com.spotalog.shared.service.rest.Constants.PHOTO_MIME_FIELD;
import static com.spotalog.shared.service.rest.Endpoints.Photos.ENDPOINT;
import static com.spotalog.shared.service.rest.Endpoints.Photos.UPLOAD;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import lombok.extern.slf4j.Slf4j;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ServingUrlOptions;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.spotalog.server.service.SpotService;
import com.spotalog.shared.exceptions.NotFoundException;
import com.spotalog.shared.model.Link;
import com.spotalog.shared.model.Photo;
import com.spotalog.shared.model.Spot;

@Slf4j
@Path(ENDPOINT)
public class PhotoResource {
	private final SpotService spotService;
	private final ImagesService imageService;
	private final Function<HttpServletRequest, String> mimeTypeExtractor;
	private final BlobstoreService blobstoreService;

	@Inject
	PhotoResource(SpotService spotService, BlobstoreService blobstoreService,
			ImagesService imageService,
			Function<HttpServletRequest, String> mimeTypeExtractor) {
		this.spotService = spotService;
		this.imageService = imageService;
		this.blobstoreService = blobstoreService;
		this.mimeTypeExtractor = mimeTypeExtractor;
	}

	@GET
	@Path("{key}")
	@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
	public Link getServingUrl(@PathParam("key") String blobKey,
			@QueryParam("o") int orientation, @QueryParam("s") int size,
			@QueryParam("c") boolean crop, @Context HttpServletResponse response)
			throws NotFoundException, IOException {
		ServingUrlOptions options = ServingUrlOptions.Builder
				.withBlobKey(new BlobKey(blobKey));

		if (orientation != 0) {
			// TODO figure out orientation
		}
		if (size > 0) {
			options.imageSize(size);
		}
		options.crop(crop);

		return new Link(this.imageService.getServingUrl(options));
	}

	@GET
	@Path(UPLOAD)
	@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
	public Link getUploadUrl(@Context HttpServletRequest request) {
		return new Link(this.blobstoreService.createUploadUrl(request
				.getRequestURI()));
	}

	@POST
	@Path(UPLOAD)
	public void addPhotos(@Context HttpServletRequest request) {
		String mimeType = this.mimeTypeExtractor.apply(request);
		String orientation = request.getParameter("orientation");
		String spotId = request.getParameter("id");

		Map<String, List<BlobKey>> ingestedPhotos = this.blobstoreService
				.getUploads(request);
		for (String key : ingestedPhotos.keySet()) {
			for (BlobKey blobKey : ingestedPhotos.get(key)) {
				try {
					Photo photo = new Photo();
					photo.setMimeType(mimeType);
					photo.setOrientation(Strings.isNullOrEmpty(orientation) ? 0
							: Integer.valueOf(orientation));
					photo.setBlobKey(blobKey.getKeyString());
					photo.setThumb(this.imageService
							.getServingUrl(ServingUrlOptions.Builder
									.withBlobKey(blobKey).crop(true)));
					Spot spot = this.spotService.readSafe(Integer
							.valueOf(spotId));
					if (spot.getPhotos() == null) {
						spot.setPhotos(Lists.<Photo> newArrayList());
					}
					spot.getPhotos().add(photo);
					this.spotService.upsert(spot);
				} catch (Exception ex) {
					log.error("Failed to upload photo: {}", ex);
					this.blobstoreService.delete(blobKey);
				}
			}
		}
	}

	@GET
	@Path(UPLOAD + "/test")
	@Produces(MediaType.TEXT_HTML)
	public Response getTestUploadForm() {
		String response;
		String postbackUrl = this.blobstoreService.createUploadUrl("/rest/"
				+ ENDPOINT + "/" + UPLOAD);
		response = String
				.format("<form name=\"%s\" action=\"%s\" method=\"POST\" enctype=\"multipart/form-data\">"
						+ "<input type=\"file\" name=\"%s\">"
						+ "<input type=\"number\" name=\"%s\">"
						+ "<input type=\"hidden\" name=\"%s\" value=\"%s\">"
						+ "<input type=\"hidden\" name=\"%s\" value=\"%s\"/><input name=\"submit\" type=\"submit\"/>"
						+ "</form>", "testForm", postbackUrl,
						PHOTO_INGEST_FIELD, "id", "orientation", 1,
						PHOTO_MIME_FIELD, "image/jpeg");
		return Response.ok(response).build();
	}
}
